#include <jni.h>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cstdint>
#include <iostream>
#include "B.h"
#include "aes.h"
#include "aes.c"
#include "md5.h"
#include "md5.cpp"

jchar* a(const char* str) {
    int length = 0;
    while (str[length] != '\0') {
        ++length;
    }

    jchar* jchars = new jchar[length + 1];
    for (int i = 0; i < length; ++i) {
        if (str[i] >= 0 && str[i] <= 0xFF) {
            jchars[i] = static_cast<jchar>(str[i]);
        }
    }
    jchars[length] = 0; // 设置结束符
    return jchars;
}

// Implementation of native method sayHello() of HelloJNI class
JNIEXPORT jcharArray JNICALL Java_a_a_a_B_a(JNIEnv *env, jobject obj, jstring str) {
    jchar* jchars = a(s1);

    // 创建Java层的char数组对象
      jcharArray charArray = env->NewCharArray(100); // 假设我们只转换前三个字符
    // 将jchars复制到Java的char数组对象中
      env->SetCharArrayRegion(charArray, 0, 100, jchars);

    return charArray;
}

std::vector<uint8_t> getBytes(JNIEnv *env, jbyteArray jbyteArray) {
    jsize length = env->GetArrayLength(jbyteArray);
    jbyte* jbyte = env->GetByteArrayElements(jbyteArray, nullptr);
    std::vector<uint8_t> srcByteArray(reinterpret_cast<uint8_t*>(jbyte), reinterpret_cast<uint8_t*>(jbyte) + length);
    env->ReleaseByteArrayElements(jbyteArray, jbyte, 0);
    return srcByteArray;
}

uint8_t* getUint8s(JNIEnv *env, jbyteArray jbyteArray) {
    jbyte* jbyte = env->GetByteArrayElements(jbyteArray, nullptr);
    uint8_t* data = reinterpret_cast<uint8_t*>(jbyte);
    return data;
}

size_t getFormatDataLengthForAes(JNIEnv *env, jbyteArray jbyteArray) {
    jsize length = env->GetArrayLength(jbyteArray);
    size_t paddedLength = ((length ) / 16+1) * 16;
    return paddedLength;
}

uint8_t* getFormatDataForAes(JNIEnv *env, jbyteArray jbyteArray) {
    jsize length = env->GetArrayLength(jbyteArray);
    jbyte* jbyte = env->GetByteArrayElements(jbyteArray, nullptr);
    uint8_t* data = reinterpret_cast<uint8_t*>(jbyte);
    size_t paddedLength = ((length ) / 16+1) * 16;
    uint8_t* paddedData = new uint8_t[paddedLength];
    memcpy(paddedData, data, length);
    memset(paddedData + length, paddedLength - length, paddedLength - length);
    env->ReleaseByteArrayElements(jbyteArray, jbyte, 0); // 释放内存
    return paddedData;
}

uint8_t* getPwd(std::vector<uint8_t> byteArray) {
    if (en_status == 1) {
        byteArray.insert(byteArray.end(), pwd.begin(), pwd.end());
    }

    size_t length = byteArray.size();
    // 计算 MD5 哈希值
    uint8_t result[16];
    uint8_t* keyArray = new uint8_t[33]; // 动态分配内存

    MD5Test::Md5Ctx Md5Ctx;
    MD5Test::md5_init(Md5Ctx);
    MD5Test::md5_update(Md5Ctx, reinterpret_cast<uint8_t*>(byteArray.data()), length);
    MD5Test::md5_final(result, Md5Ctx);

    // 将 MD5 哈希值转换为十六进制字符串
    for (int i = 0; i < 16; ++i) {
        sprintf(reinterpret_cast<char*>(keyArray + (i * 2)), "%02x", result[i]);
    }
    keyArray[32] = 0; // 设置结束符

    return keyArray;
}

std::vector<uint8_t> md5Hash(std::vector<uint8_t> byteArray) {
    size_t length = byteArray.size();
    // 计算 MD5 哈希值
    uint8_t result[16];
    uint8_t* keyArray = new uint8_t[33]; // 动态分配内存

    MD5Test::Md5Ctx Md5Ctx;
    MD5Test::md5_init(Md5Ctx);
    MD5Test::md5_update(Md5Ctx, reinterpret_cast<uint8_t*>(byteArray.data()), length);
    MD5Test::md5_final(result, Md5Ctx);

    // 将 MD5 哈希值转换为十六进制字符串
    for (int i = 0; i < 16; ++i) {
        sprintf(reinterpret_cast<char*>(keyArray + (i * 2)), "%02x", result[i]);
    }
    keyArray[32] = 0; // 设置结束符
    // 将 keyArray 转换为 std::vector<uint8_t>
    std::vector<uint8_t> keyVector(keyArray, keyArray + 32);
    // 释放原始数组
    delete[] keyArray;
    return keyVector;
}

void encrypt(uint8_t* keyArray, uint8_t* data,int length) {
    AES_ctx ctx;
    AES_init_ctx(&ctx, keyArray);
     for (size_t i = 0; i < length; i += 16) {
        // 加密
        AES_ECB_encrypt(&ctx, data+i);
    }
}

void decrypt(uint8_t* keyArray, uint8_t* data,int length) {
    // 初始化 AES 上下文
    AES_ctx ctx;
    AES_init_ctx(&ctx, keyArray);

     for (size_t i = 0; i < length; i += 16) {
        // 解密
        AES_ECB_decrypt(&ctx, data+i);
    }
}

// 声明 JNI 函数
JNIEXPORT jbyteArray JNICALL Java_a_a_a_B_e(JNIEnv *env, jobject obj, jbyteArray src, jbyteArray key) {
    uint8_t* data = getFormatDataForAes(env, src);
    std::vector<uint8_t> keyByteArray = getBytes(env, key);
    // 添加密码
    keyByteArray.insert(keyByteArray.end(), pwd.begin(), pwd.end());
    en_status=0;// 清除解密初始化标志
    uint8_t* keyArray = getPwd(keyByteArray);
    std::cout << "keyArray 加密密指向的值是: " << en_status << " " << *keyArray << std::endl;
    // 初始化 AES 上下文
    size_t paddedLength = getFormatDataLengthForAes(env, src);
    encrypt(keyArray, data,paddedLength);
    // 创建一个新的 Java 字节数组来存储加密后的结果
    jbyteArray resultArray = env->NewByteArray(paddedLength);
    env->SetByteArrayRegion(resultArray, 0, paddedLength, reinterpret_cast<const jbyte*>(data));

    delete[] keyArray; // 释放内存
    delete[] data; // 释放内存
    return resultArray;
}

// 声明 JNI 函数
JNIEXPORT jbyteArray JNICALL Java_a_a_a_B_d(JNIEnv *env, jobject obj, jbyteArray src, jbyteArray key) {
    // 获取输入字节数组的长度
    jsize length = env->GetArrayLength(src);

//        std::cout << "Java_a_a_a_B_d st" << std::endl;
    // 复制密文数据
    uint8_t* data = getUint8s(env, src);
    std::vector<uint8_t> keyByteArray = getBytes(env, key);

//        std::cout << "Java_a_a_a_B_d keyByteArray" << keyByteArray.size() << std::endl;
    uint8_t* keyArray = getPwd(keyByteArray);
//        std::cout << "data 指向的值是: " << *data << std::endl;
        std::cout << "keyArray 解密指向的值是: " << en_status << " " << *keyArray << std::endl;

    decrypt(keyArray, data,length);
//    AES_ctx ctx;
//    AES_init_ctx(&ctx, keyArray);
//    // 解密
//    AES_ECB_decrypt(&ctx, data);

//        std::cout << "Java_a_a_a_B_d length" << length << std::endl;
//        std::cout << "data 指向的值是: " << *data << std::endl;
//        std::cout << "data[length - 1] 指向的值是: " << reinterpret_cast<const uint8_t>(data[length - 1]) << std::endl;

    // 去除 PKCS5 填充
    uint8_t paddingValue = data[length - 1];
//        std::cout << "paddingValue 指向的值是: " << paddingValue << std::endl;
    size_t originalLength = length - paddingValue;
//        std::cout << "originalLength 指向的值是: " << originalLength << std::endl;
    // 创建一个新的 Java 字节数组来存储解密后的结果
    jbyteArray resultArray = env->NewByteArray(originalLength);
    env->SetByteArrayRegion(resultArray, 0, originalLength, reinterpret_cast<const jbyte*>(data));

    delete[] keyArray; // 释放内存
    return resultArray;
}

bool areVectorsEqual(const std::vector<uint8_t>& vec1, const std::vector<uint8_t>& vec2) {
    if (vec1.size() != vec2.size()) {
        return false;
    }
    for (size_t i = 0; i < vec1.size(); ++i) {
        if (vec1[i] != vec2[i]) {
            return false;
        }
    }
    return true;
}

JNIEXPORT void JNICALL Java_a_a_a_B_i(JNIEnv *env, jobject obj, jbyteArray inputArray) {
    std::vector<uint8_t> input = getBytes(env, inputArray);
    std::vector<uint8_t> hash = md5Hash(input);
    for (uint8_t byte : hash) {
        std::cout << static_cast<int>(byte) << " ";
    }
    std::cout << std::endl;
    if (areVectorsEqual(hash, file_hash)) {
        en_status = 1;
        std::cout << "file hash is right" << en_status << std::endl;
    } else {
        en_status = 0;
        std::cout << "file hash is wrong" << en_status << std::endl;
    }
}
